package com.cn.por.util.html;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.*;

/**
 * 解析swagger地址，获取到接口信息。
 * 业务流程， 用户传入接口地址或和接口名称，以及一个时间流水号，解析地址，并进行保存（用前端传的时间流水号和swagger地址作为id），解析完成
 * 后，根据接口名称进行查找，返回对应的接口信息，用户再点击行显示相关api代码，进行复制。当用户点击刷新按钮时，清空解析的信息，并传入新的流水号
 * 作为接口信息列表的id号。
 *
 * {
 * 	"id": [{"aController":"省级统筹大屏", func:[{method:get,query:id,name,body:aDto}}]]
 *
 * }
 * [ "省级统筹大屏","市级统筹大屏" ]
 */
public class SwaggerParseUtil {

    public static void main(String[] args) {

        List<ModelApi> list = parseSwagger("http://localhost:8081/por/v2/api-docs", "1", "获取api信息");

        getElementUiApi(list);
    }

    /**
     *
     *  "id": [{"aController":"省级统筹大屏", func:[{method:get,query:id,name,body:aDto}}]]
     *
     *
     */
    private static final Map<String, List<ModelApi>> modelApiMap = new HashMap<>();

    /**
     * "id":["省级统筹大屏"]
     */
    private static final Map<String,String[]> modelApiName = new HashMap<>();

    /**
     * 解析swagger
     */
    public static List<ModelApi> parseSwagger(String url,String id,String name){
        if(StrUtil.isEmpty(url)){
            throw new RuntimeException("swagger-ui的【url】地址不能为空");
        }
        if(StrUtil.isEmpty(id)){
            throw new RuntimeException("【id】不能为空");
        }
        String swaggerJson = fetchSwaggerJson(url);
        List<ModelApi> result = new ArrayList<>();
        /**
         * 获取到swaggerJson转换的java对象
         */
        List<ModelApi> modelApis = modelApiMap.get(id+url);
        if(null==modelApis || modelApis.size()==0){
            parseInterfaces(swaggerJson,id,url);
        }
        modelApis = modelApiMap.get(id+url);
        if(StrUtil.isEmpty(name)){
            result = modelApis;
        }else{
            String[] strings = modelApiName.get(id+url);
            for (int i = 0; i < strings.length; i++) {
                String item = strings[i];
                if(item.contains(name)){
                    result.add(modelApis.get(i));
                }
            }
        }
        return result;
    }

    /**
     * 根据swagger地址获取对应的json信息
     * @param swaggerUrl
     * @return
     */
    private static String fetchSwaggerJson(String swaggerUrl) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(headers);
        /**
         * 如果入参是普通的swagger地址，需要获取到对应下swagger-resources地址
         */
        String urlEnd=swaggerUrl;
        if(swaggerUrl.contains("swagger-ui")){
            //协议类型
            String protocol = swaggerUrl.substring(0,swaggerUrl.indexOf("http")!=-1?4:0);
            if(StrUtil.isEmpty(protocol)){
                protocol = swaggerUrl.substring(0,swaggerUrl.indexOf("https")!=-1?5:0);
            }
            protocol = protocol+"://";
            String[] urlSplit = swaggerUrl.replace(protocol,"").split("/");
            String u = protocol+urlSplit[0] +"/"+ urlSplit[1]+"/swagger-resources";
            ResponseEntity<String> resource =  restTemplate.exchange(u,HttpMethod.GET, entity, String.class);
            String body = resource.getBody();
            JSONArray objects = JSONUtil.parseArray(body);
            Map strArray = (Map)objects.get(0);
            String urlDocs = strArray.get("url")+"";
            urlEnd = protocol+urlSplit[0]+"/"+urlSplit[1]+urlDocs;
        }

        ResponseEntity<String> response = restTemplate.exchange(urlEnd, HttpMethod.GET, entity, String.class);
        return response.getBody();
    }

    /**
     * 将swaggerJson解析为java对象
     * @param swaggerJson
     * @param id
     * @throws Exception
     */
    private static  void parseInterfaces(String swaggerJson,String id,String urlSwagger){
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = null;
        try {
            rootNode = objectMapper.readTree(swaggerJson);
        } catch (IOException e) {
            throw new RuntimeException("获取swaggerJson异常"+ e);
        }
        List<ModelApi>  modelList=new ArrayList<>();
        StringBuffer sb = new StringBuffer();
        /**
         * paths属性就是每个接口的详情了
         */
        JsonNode pathsNode = rootNode.get("paths");
        if (pathsNode!= null && pathsNode.isObject()) {

            ModelApi modelApi = new ModelApi();
            List<FunctionDesc> funList = new ArrayList<>();
            String oldBaseUrl ="";
            Iterator<Map.Entry<String, JsonNode>> fields = pathsNode.fields();
            while (fields.hasNext()){
                Map.Entry<String, JsonNode> next = fields.next();
                /**
                 * 将请求路径拆分为基本路径和子路径
                 */
                String url = next.getKey();
                String[] split = url.split("/");
                FunctionDesc fun = new FunctionDesc();
                fun.setUrlSuffix(split[split.length-1]);
                String baseUrlNew = url.replace("/"+fun.getUrlSuffix(),"");
                if(StrUtil.isEmpty(oldBaseUrl)){
                    oldBaseUrl= baseUrlNew;
                }else{
                    /**
                     * 当基本路径发生变化时，需要新建一个modelApi
                     */
                    if(!oldBaseUrl.equals(baseUrlNew)){
                        sb.append(modelApi.getTag()+",");
                        ModelApi modelApiAdd = null;
                        List<FunctionDesc> addFun = new ArrayList<>();
                        try {
                            modelApiAdd = (ModelApi) BeanUtils.cloneBean(modelApi);
                            for (FunctionDesc el: funList){
                                addFun.add((FunctionDesc) BeanUtils.cloneBean(el));
                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        modelApiAdd.setFunList(addFun);
                        modelList.add(modelApiAdd);
                        modelApi = new ModelApi();
                        funList = new ArrayList<>();
                        oldBaseUrl = baseUrlNew;
                    }
                }
                modelApi.setBaseUrl(baseUrlNew);
                JsonNode value = next.getValue();
                Iterator<Map.Entry<String, JsonNode>> fields1 = value.fields();
                while (fields1.hasNext()){
                    Map.Entry<String, JsonNode> nextMethod = fields1.next();
                    fun.setMethod(nextMethod.getKey());
                    JsonNode functionMsg = nextMethod.getValue();
                    JsonNode jsonNode = functionMsg.get("tags");
                    fun.setFuncDesc(null!=functionMsg.get("summary")?functionMsg.get("summary").asText():null);
                    fun.setFuncName(fun.getUrlSuffix());
                    JsonNode jsonNodeParam = functionMsg.get("parameters");
                    if(null!=jsonNodeParam){
                        for(JsonNode item : jsonNodeParam){
                            /**
                             * 参数通过body传递,通过query传递
                             */
                            JsonNode paramterBody = item.get("in");
                            if(null!=paramterBody && paramterBody.asText().equals("body")){
                                fun.setParamterBody(item.get("name").asText());
                            }
                            if(null!=paramterBody && paramterBody.asText().equals("query")){
                                fun.setParamterQuery(null!=fun.getParamterQuery()?fun.getParamterQuery()+item.get("name").asText()+",":item.get("name").asText()+",");
                            }
                        }
                    }

                    if(StrUtil.isEmpty(modelApi.getTag())){
                        modelApi.setTag(jsonNode.get(0).asText());
                    }
                    if(StrUtil.isNotEmpty(fun.getParamterQuery())){
                        fun.setParamterQuery(fun.getParamterQuery().substring(0,fun.getParamterQuery().length()-1));
                    }
                    funList.add(fun);

                    fields1.remove();
                }
                fields.remove();
            }
            if(null!=modelApi && null!=modelApi.getBaseUrl()){
                modelApi.setFunList(funList);
                modelList.add(modelApi);
                sb.append(modelApi.getTag()+",");
            }
        }
        modelApiMap.put(id+urlSwagger,modelList);
        String st = sb.toString();
        if(StrUtil.isNotEmpty(st)){
            modelApiName.put(id+urlSwagger,(st.substring(0,st.length()-1).split(",")));
        }else{
            throw new RuntimeException("转换swaggerJson异常没有获取到对应的接口信息");
        }
    }


    /**
     * 获取api文件集合
     * @param modelApis
     * @return
     */
    public static  List<ElementUiApi>  getElementUiApi(List<ModelApi> modelApis){
        if(null==modelApis || modelApis.size()==0){
            return null;
        }
        List<ElementUiApi> result = new ArrayList<>();

        String startOne="import request from '@/utils/request'";
        String baseUrl="const BASE_URL = '{baseUrl}'\n";
        String postFunc =
                "export function {funcName}(params) { \n" +
                        "   return request({\n"+
                        "       url: BASE_URL + {funcUrl},\n"+
                        "       method: 'post',\n"+
                        "       data: params\n"+
                        "   })\n"+
                        "}\n";

        String getFunc =
                "export function {funcName}(params) { \n" +
                        "   return request({\n"+
                        "       url: BASE_URL + {funcUrl},\n"+
                        "       method: 'get'\n"+
                        "   })\n"+
                        "}\n";

        /**
         * 遍历生成多个api文件
         */
        for (ModelApi item : modelApis){
            ElementUiApi elementUi = new ElementUiApi();
            StringBuffer sb= new StringBuffer();
            StringBuffer sbImport = new StringBuffer();
            sbImport.append("import {");
            sb.append(startOne+"\n");
            /**
             * 拼接基本路径
             */
            sb.append(baseUrl.replace("{baseUrl}",item.getBaseUrl()));
            List<FunctionDesc> funList = item.getFunList();
            elementUi.setTag(item.getTag());
            elementUi.setDesc(item.getDesc());
            elementUi.setBaseUrl(item.getBaseUrl());
            /**
             * 循环添加方法
             */
            for(int i=0;i<funList.size();i++){
                FunctionDesc el =  funList.get(i);
                String func = "";
                if("get".equals(el.getMethod())){
                    func = getFunc;
                }else{
                    func = postFunc;
                }
                String queryStr = el.getParamterQuery();
                StringBuffer urlBf = new StringBuffer();
                urlBf.append("'/"+el.getUrlSuffix()+"'");
                if(StrUtil.isNotEmpty(queryStr)){
                    String[] split = queryStr.split(",");
                    for (int j = 0; j < split.length; j++) {
                        if(j==0){
                            urlBf.append("+'?"+split[j]+"=' + params."+split[j]);
                        }else{
                            urlBf.append("+'&"+split[j]+"=' "+"+ params."+split[j]);
                        }
                    }
                }
                if(StrUtil.isNotEmpty(el.getFuncDesc())){
                    sb.append("//"+el.getFuncDesc()+"\n");
                }
                if(i==funList.size()-1){
                    sbImport.append(el.getFuncName());
                }else{
                    sbImport.append(el.getFuncName()+",");
                }
                sb.append(func.replace("{funcName}",genFunName(el.getFuncName())).replace("{funcUrl}",urlBf.toString()));
            }
            sbImport.append("} from \"@/api/\"");
            elementUi.setImportStr(sbImport.toString());
            elementUi.setApiStr(sb.toString());
            elementUi.setMethods(elementUi.getMethods());
            result.add(elementUi);
        }
        return result;
    }

    /**
     * 避开关键字
     * @param name
     * @return
     */
    private static String genFunName(String name){
        String keyName ="delete";
        if(keyName.contains(name)){
            return name+"Some";
        }
        return name;
    }
}
